import fs from 'fs-extra'
import path from 'path'
import { argbLightGreen, getColLabel, SheetInfo, writeXlsx } from "./xlsxUtil"

declare type StrNum = string | number
declare type FObject = { [key: string]: StrNum }

export class Lua2xlsx {
    public async parseAll (input: string, output: string): Promise<void> {
        await fs.ensureDir(output)
        const files = await fs.readdir(input)
        let skip = true;
        for (const f of files) {
            if (f.endsWith('.json')) {
                const file = path.join(input, f)
                console.log('Processing:', file)
                const raw = await fs.readJSON(file)
                let objArr = raw
                if (!(raw instanceof Array)) {
                    objArr = Object.values(raw)
                }
                await this.objArr2Xlsx(objArr, path.join(output, f.replace('.json', '.xlsx')))
            }
        }
    }

    private async objArr2Xlsx (objArr: any[], outFile: string): Promise<void> {
        const totalKeys: string[] = []
        const keyMap: { [rawKey: string]: string } = {}
        const fos: FObject[] = []
        const wchs: number[] = []
        for (const obj of objArr) {
            const flatterned: FObject = {}
            this.flattern(obj, '', flatterned)
            fos.push(flatterned)
            const keys = Object.keys(flatterned)
            for (const k of keys) {
                if (!totalKeys.includes(k)) {
                    totalKeys.push(k)
                    const nk = k.replace(/\.\d+\./g, '.')
                    if (nk !== k) {
                        keyMap[nk] = k
                    }
                    wchs.push(16)
                }
            }
        }
        console.log('processing single arrays...')
        // 简单处理下单个数组的问题
        for (let i = totalKeys.length - 1; i >= 0; i--) {
            if (keyMap[totalKeys[i]]) {
                totalKeys.splice(i, 1)
            } else {
                wchs.push(10)
            }
        }
        totalKeys.sort()
        // 补充默认值
        console.log('processing default values...');
        const defaultMap: { [key: string]: StrNum } = {}
        for (const fo of fos) {
            for (const key in fo) {
                const value = fo[key]
                if (typeof(value) === 'string') {
                    defaultMap[key] = ''
                } else {
                    defaultMap[key] = 0
                }
            }
        }
        const rows: StrNum[][] = [totalKeys]
        for (const fo of fos) {
            const row: StrNum[] = []
            for (const k of totalKeys) {
                const v = fo[k]
                if (v == null) {
                    row.push('')
                } else {
                    row.push(v)
                }
            }
            rows.push(row)
        }
        console.log('writing xlsx...')
        const sheets: SheetInfo<StrNum>[] = [{ aoa: rows, name: 'Lua2xlsx', wchs, decideStyle: (ws, sheetInfo)=>{
            for (let i = 0, len = totalKeys.length; i < len; i++) {
                const label = getColLabel(i)
                const cell = ws[`${label}1`]
                if (cell != null) {
                    cell.s = { fill: { patternType: 'solid', bgColor: { rgb: argbLightGreen }, fgColor: { rgb: argbLightGreen } } };
                }
            }
        } }]
        await writeXlsx(outFile, sheets)
    }

    private flattern (obj: any, prefix: string, out: FObject): void {
        let sid = 0;
        for (const key in obj) {
            const value = obj[key]
            if (!(obj instanceof Array) && key.match(/^\d+$/) && typeof(value) !== 'object') {
                let key1 = `${sid}.k`
                let key2 = `${sid}.v`
                if (prefix !== '') {
                    key1 = prefix + '.' + key1
                    key2 = prefix + '.' + key2
                }
                out[key1] = key
                out[key2] = value
            } else {
                let traceKey = key
                if (prefix !== '') traceKey = prefix + '.' + traceKey
                if (typeof(value) === 'object') {
                    if (obj instanceof Array && obj.length > 3) obj.length = 3
                    this.flattern(value, traceKey, out)
                } else {
                    out[traceKey] = value
                }                
            }
            sid++
        }
    }
}